package com.cskaoyan.javase.oop3._2inner._5lambda._1basic;

import com.sun.org.apache.regexp.internal.RE;

/**
 * Lambda表达式的简化
 * 首先Lambda表达式之所以能够在基础语法的基础上继续简化,前提是Lambda表达式仅需要实现一个固定的抽象方法.
 * 当然简化也不能影响Lambda表达式的语义,不能歧义
 *
 * Lambda表达式的语法:
 * () -> {}
 *
 * 1.()中写的是抽象方法的形参列表,这里能不能简化呢?
 *      形参列表的数据类型是可以省略的
 *      但是形参的名字不能省略
 *      特殊的,如果形参列表只有一次,那么小括号也可以省略
 *      当然如果是无参,不能省略小括号
 *
 *
 * 2.{}中写的抽象方法重写的方法,它能不能简化?
 * 是可以的
 * 当重写方法的方法体只有一条语句时,可以省略大括号
 * 特殊的,当这一条语句是方法的返回值语句时,
 * 可以连大括号和return关键字,一起省略.直接写返回值
 *
 * 以上Lambda表达式的简化,在实际开发中是不多见的,因为重写方法的方法体往往会很长,不是一行代码能写完的,这个时候大括号就不能省略了.
 * Lambda表达式就会变得很臃肿,为了避免这种情况出现,Lambda表达式的实现可以直接指向一个已经存在的方法.
 *
 * 什么样的方法能够匹配Lambda表达式中抽象方法的实现?
 * 在方法中:
 *      1.修饰符列表没有很大影响.只需要有访问权限就够了.尤其注意static没有影响
 *      2.返回值类型需要一样.
 *      3.方法名没有影响,无所谓.
 *      4.形参列表需要一样
 *      5.方法体随便.
 *
 * Lambda表达式指向一个已存在方法的实现,语法是:
 * (形参列表) -> 一个已存在的方法(形参列表);
 * 细节:
 *      static方法属于类
 *      非static方法属于对象
 *      所以指向已存在方法时,如果是静态方法
 *      用类名.访问
 *      成员方法
 *      用对象名.访问
 *
 * 以上lambda表达式指向一个方法的实现,还可以继续简化,语法是:
 * 接口名 引用 = 方法的归属者::一个已经存在的方法的方法名;
 * 这种lambda表达式的书写形式,称之为方法引用
 *
 * 注意,只写方法名,不带形参列表!
 * 何为方法的归属者:
 *      1.static方法属于类,写类名
 *      2.成员方法属于对象,写对象名
 *
 * lambda表达式指向一个方法实现,只要这个方法存在就可以了,源代码中的方法也可以指向.
 *
 * 以上lambda表达式的简化,就到此为止了.
 *
 * 注意事项:
 *      1.和局部内部类一样,访问方法的局部变量,是一个常量
 *      2.Lambda表达式的重写方法体,和lambda表达式所处的方法,共用一个作用域.
 *          lambda表达式重写方法体中,不能定义方法外部已经定义的局部变量
 *          是lambda表达式语法中自身重写方法的方法体,就是语法中的那个大括号
 *          方法引用不受影响
 *
 *
 * @since 09:32
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        int value  = 10;
        /*INoReturnTwoParam ip1 = (int a, int b) -> {
            System.out.println("a和b的和是: " + (a + b));
        };
        ip1.test(10, 10);*/
        // 以上简化成
        INoReturnTwoParam ip1 = (a, b) -> {
            // int value = 200;
            // System.out.println(value++);
            System.out.println("a和b的和是: " + (a + b));
        };
        ip1.test(10, 10);

        System.out.println("---------------------");
        /*INoReturnOneParam ip2 = (a) -> {
            System.out.println(a + "是一个大笨蛋!");
        };
        ip2.test(10); */
        // 以上简化成
        INoReturnOneParam ip2 = a -> {
            System.out.println(a + "是一个大笨蛋!");
        };
        ip2.test(10);
        // 以上继续简化
        INoReturnOneParam ip3 = a -> System.out.println(a + "是一个大笨蛋!");
        ip2.test(10);

        System.out.println("----------------------");
        IHasReturnOneParam ip4 = a -> a;
        System.out.println(ip4.method(10));
        System.out.println("-----------------------");
        IHasReturnTwoParam ip5 = (a, b) -> a + b;
        System.out.println(ip5.test(10, 20));

        System.out.println("--------------------");
        INoReturnNoParam ip6 = () -> Demo.myTest();
        ip6.test();
        INoReturnNoParam ip7 = () -> new Demo().myTest2();
        ip7.test();
        IHasReturnTwoParam ip8 = (a, b) -> new Demo().myTest3(a, b);
        System.out.println(ip8.test(1, 1));

        System.out.println("-------------------------");
        // 以上方法引用可以简化为
        INoReturnNoParam ip9 = Demo::myTest;
        ip9.test();
        INoReturnNoParam ip10 = new Demo()::myTest2;
        ip10.test();
        IHasReturnTwoParam ip11 = new Demo()::myTest3;
        System.out.println(ip11.test(1, 1));

        System.out.println("------------------------------");

        // lambda表达式的实现指向已存在的源码中的方法
        // System.out是一个对象 out是System类的一个静态成员
        // println属于对象System.out
        INoReturnOneParam ip12 = System.out :: println;
        ip12.test(1000);
    }

    private static void myTest() {
        System.out.println("hello world!");
    }

    private void myTest2() {
        System.out.println("hello 666!");
    }

    private int myTest3(int a, int b) {
        int sum = a + b;
        return sum * 100;
    }
}

//无返回值无参数的功能接口
@FunctionalInterface
interface INoReturnNoParam {
    void test();
}

//无返回值有一个参数的功能接口
@FunctionalInterface
interface INoReturnOneParam {
    void test(int a);
}

//无返回值两个参数的功能接口
@FunctionalInterface
interface INoReturnTwoParam {
    void test(int a, int b);
}

//有返回值无参数的功能接口
@FunctionalInterface
interface IHasReturnNoParam {
    int test();
}

//有返回值一个参数的功能接口
@FunctionalInterface
interface IHasReturnOneParam {
    int method(int a);
}

//有返回值两个参数的功能接口
@FunctionalInterface
interface IHasReturnTwoParam {
    int test(int a, int b);
}